﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Windows.Media.Imaging;

namespace Player
{
    public class PreviewProgressUpdatedEventArgs : EventArgs
    {
        public PreviewProgressUpdatedEventArgs(BitmapSource image, string text)
        {
            Image = image;
            Text = text;
        }

        public BitmapSource Image { get; protected set; }
        public string Text { get; protected set; }
    }

    public class PreviewThread : WorkerThread<PreviewProgressUpdatedEventArgs>
    {
        private FrameBuffer m_frames;

        // Don't put privewEngine into the Run method because
        // the GC might have garbage collect the RenderEngine while we are doing TakeSnapshot()
        RenderEngine m_previewEngine;

        public PreviewThread(FrameBuffer frames)
        {
            m_frames = frames;
        }

        /// <summary>
        /// Playing thread never stops.  It keeps reading from the buffer.
        /// If there is no data in the buffer, playing thread is blocked until some data are written to the buffer
        /// This is useful for live replay
        /// </summary>
        protected override void Run(params object[] args)
        {
            try
            {

                Update(new PreviewProgressUpdatedEventArgs(null, "Loading..."));

                // Fast forward to the start time
                SessionBase session = (SessionBase)args[0];
                long start = (long)args[1];
                m_previewEngine = session.CreateRenderEngine();

                IEnumerable<FrameBase> frames = m_frames.GetFrames(start);

                FrameBase current = null;
                foreach (FrameBase item in frames)
                {
                    current = item;
                    m_previewEngine.Process(current);
                    Thread.Sleep(0);
                    if (ShouldStop) return;
                }

                // Make a fake frame to make sure the time is displayed correctly after we render the screen
                if (current != null)
                {
                    DateTime systemStartTime = current.SystemTime - new TimeSpan(current.TimeStamp - start);
                    BitmapSource bmp = m_previewEngine.TakeSnapshot();
                    bmp.Freeze();
                    Log.Trace("Preview time: {0}", systemStartTime.ToLocalTime());
                    Update(new PreviewProgressUpdatedEventArgs(bmp, systemStartTime.ToLocalTime().ToString()));
                }
                else
                {
                    // The data is not buffered yet.  Now, we need to guess
                    DateTime guessedTime = session.StartTime + session.GetElapsedTime(start);
                    Log.Trace("Preview time: {0}", guessedTime.ToLocalTime());
                    Update(new PreviewProgressUpdatedEventArgs(null, guessedTime.ToLocalTime().ToString()));
                }
            }
            catch (Exception e)
            {
                Update(new PreviewProgressUpdatedEventArgs(null, "Unable to preview.  Try again."));
                Log.Error("Error during Preview: " + e);
            }
        }
    }
}
